﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using TestesFixacao.Dominio.Modelos;

namespace TestesFixacao.Dominio.Repositorios.ADO
{
    public class RepositorioAdoQuestao : IRepositorioQuestao
    {
        private RepositorioAdoMateria _repositorioMateria = new RepositorioAdoMateria();

        #region querys

        #region QuerysQuestao

        private const string SqlInsereQuestao =
            @"INSERT INTO [TestesFx].[dbo].[TBQuestao]
                ([bimestre],[enunciado], [numeroMateria])
            VALUES ({0}bimestre,{0}enunciado, {0}numeroMateria)";

        private const string SqlEditaQuestao =
            @"UPDATE [TBQUESTAO]
                SET [BIMESTRE] = {0}BIMESTRE,
                    [ENUNCIADO] = {0}ENUNCIADO
                WHERE [NUMERO] = {0}NUMERO";

        private const string SqlExcluiQuestao =
           @"DELETE FROM [TBQUESTAO]
                WHERE [NUMERO] = {0}NUMERO";

        private const string SqlExcluirAlternativaQuestao =
            @"DELETE FROM [TBALTERNATIVA]
                WHERE [NUMEROQUESTAO] = {0}NUMEROQUESTAO";

        private const string SqlSelecionaTodasQuestao =
           @"SELECT Questao.numero
                      ,Questao.bimestre
                      ,Questao.enunciado
                      ,Questao.numeroMateria
                FROM TBQuestao As Questao inner join TBMateria As Materia
                ON Questao.numeroMateria = Materia.numero";

        private const string SqlSelecionaQuestaoPorNumero =
           @"SELECT Questao.numero
                      ,Questao.bimestre
                      ,Questao.enunciado
                      ,Materia.nome
                      ,Questao.numeroMateria
                FROM TBQuestao As Questao inner join TBMateria As Materia
                ON Questao.numeroMateria = Materia.numero
            WHERE Questao.numero = {0}NUMERO";

        private const string SqlSelecionaQuestaoPorMateria = @"SELECT Questao.numero
                      ,Questao.bimestre
                      ,Questao.enunciado
                      ,Questao.numeroMateria
                FROM TBQuestao As Questao inner join TBMateria As Materia
                ON Questao.numeroMateria = Materia.numero
                WHERE Questao.numeroMateria = {0}numeroMateria";

        #endregion QuerysQuestao

        #region QuerysAlternativas

        private const string SqlSelecionaTodasAlternativasPorQuestao = @"SELECT [numero]
                                                                          ,[resposta]
                                                                          ,[letra]
                                                                          ,[eCorreta]
                                                                          ,[numeroQuestao]
                                                                      FROM [TBAlternativa]
                                                                      WHERE [numeroQuestao] = {0}numeroQuestao";

        private const string SqlInsereAlternativa = @"INSERT INTO [TBALTERNATIVA]
                                                           ([RESPOSTA],[LETRA],[ECORRETA],[NUMEROQUESTAO])
                                                     VALUES
                                                           ({0}RESPOSTA, {0}LETRA, {0}ECORRETA, {0}NUMEROQUESTAO)";

        private const string SqlEditaAlternativa = @"UPDATE [TBAlternativa]
                                                       SET [resposta] = {0}resposta,
                                                           [letra] = {0}letra,
                                                           [eCorreta] = {0}eCorreta,
                                                           [numeroQuestao] = {0}numeroQuestao
                                                     WHERE [numero] = {0}numero";

        private const string SqlVerificaExisteAlternativa = @"SELECT Count(numero)
                                                  FROM [TBAlternativa]
                                                  WHERE [numeroQuestao] = {0}numeroQuestao
	                                                and [letra] = {0}letra";

        #endregion QuerysAlternativas

        #endregion querys

        public void Adiciona(Questao questao)
        {
            //Ao adicionar questão deve ser adicionadas as alternativas.
            questao.Numero = Db.Insert(SqlInsereQuestao, GetParametrosQuestao(questao));

            foreach (Alternativa item in questao.Alternativas)
            {
                Db.Insert(SqlInsereAlternativa, GetParametrosAlternativas(item, questao.Numero));
            }
        }

        public void Edita(Questao questao)
        {
            Db.Update(SqlEditaQuestao, GetParametrosQuestao(questao));

            foreach (Alternativa item in questao.Alternativas)
            {
                bool atualiza = Db.Verify(SqlVerificaExisteAlternativa,
                    new object[] { "numeroQuestao", questao.Numero, "letra", item.Letra });

                if (atualiza)
                {
                    Db.Update(SqlEditaAlternativa, GetParametrosAlternativas(item, questao.Numero));
                }
                else
                    Db.Insert(SqlInsereAlternativa, GetParametrosAlternativas(item, questao.Numero));
            }
        }

        public void Exclui(Questao questao)
        {
            try
            {
                Db.Delete(SqlExcluirAlternativaQuestao, new object[] { "numeroquestao", questao.Numero });
                Db.Delete(SqlExcluiQuestao, new object[] { "numero", questao.Numero });
            }
            catch (Exception e)
            {
                throw new Exception("A questão não pode ser excluida pois está relacionada a um Teste.", e);
            }
        }

        public Questao SelecionaPorId(int numero)
        {
            Questao questao;

            questao = Db.Get(SqlSelecionaQuestaoPorNumero, ConverterQuestao, new object[] { "Numero", numero });

            questao.Alternativas = Db.GetAll<Alternativa>(SqlSelecionaTodasAlternativasPorQuestao,
                ConverterAlternativa, new object[] { "numeroQuestao", questao.Numero });

            questao.Materia = _repositorioMateria.SelecionaPorId(questao.Materia.Numero);

            return questao;
        }

        public List<Questao> SelecionaTodos()
        {
            List<Questao> questoes = Db.GetAll<Questao>(SqlSelecionaTodasQuestao, ConverterQuestao);

            foreach (Questao item in questoes)
            {
                item.Alternativas = Db.GetAll<Alternativa>(SqlSelecionaTodasAlternativasPorQuestao,
                ConverterAlternativa, new object[] { "numeroQuestao", item.Numero });

                item.Materia = _repositorioMateria.SelecionaPorId(item.Materia.Numero);
            }

            return questoes;
        }

        public List<Questao> SelecionaTodosPorMateria(Materia materia)
        {
            List<Questao> questoes = Db.GetAll<Questao>(SqlSelecionaQuestaoPorMateria,
                ConverterQuestao, new object[] { "numeroMateria", materia.Numero });

            foreach (Questao item in questoes)
            {
                item.Alternativas = Db.GetAll<Alternativa>(SqlSelecionaTodasAlternativasPorQuestao,
                ConverterAlternativa, new object[] { "numeroQuestao", item.Numero });

                item.Materia = materia;
            }

            return questoes;
        }

        public Questao ConverterQuestao(IDataReader reader)
        {
            Questao questao = new Questao();

            questao.Numero = Convert.ToInt32(reader["numero"]);
            questao.Enunciado = Convert.ToString(reader["enunciado"]);
            questao.Bimestre = Convert.ToInt32(reader["bimestre"]);
            questao.Materia = new Materia() { Numero = Convert.ToInt32(reader["numeroMateria"]) };

            return questao;
        }

        public Alternativa ConverterAlternativa(IDataReader reader)
        {
            Alternativa alternativa = new Alternativa();

            alternativa.Numero = Convert.ToInt32(reader["numero"]);
            alternativa.Letra = Convert.ToChar(reader["letra"].ToString());
            alternativa.Resposta = Convert.ToString(reader["resposta"]);
            alternativa.Correta = Convert.ToBoolean(reader["eCorreta"]);

            return alternativa;
        }

        private object[] GetParametrosQuestao(Questao questao)
        {
            return new object[]
            {
                "numero", questao.Numero,
                "enunciado", questao.Enunciado,
                "bimestre", questao.Bimestre,
                "numeroMateria", questao.Materia.Numero
            };
        }

        private object[] GetParametrosAlternativas(Alternativa alternativa, int numeroQuestao)
        {
            return new object[]
            {
                "numero", alternativa.Numero,
                "resposta", alternativa.Resposta,
                "letra", alternativa.Letra,
                "eCorreta", alternativa.Correta,
                "numeroQuestao", numeroQuestao
            };
        }
    }
}